// To compile: g++ -o fileToNxt.exe fileToNxt.cc

// C++ includes
#include <iostream>
#include <fstream>
#include <string>

// Unix includes
#include <fcntl.h>
#include <termios.h>

// C includes
#include <cstdlib>
#include <cstring>

using namespace std;

int openSerial(char* device) {
  int comfd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
  if (comfd < 0) {
    perror(device);
    exit(-1);
  }

  struct termios comSettings;
  comSettings.c_cflag = B57600 | CS8 | CLOCAL | CREAD;
  comSettings.c_iflag = IGNPAR;
  comSettings.c_oflag = 0;
  comSettings.c_lflag = 0;
  comSettings.c_cc[VMIN]=1;
  comSettings.c_cc[VTIME]=0;
  tcflush(comfd, TCIFLUSH);
  tcsetattr(comfd,TCSANOW,&comSettings);

  return comfd;
}

void matchExpectedChars(int comfd, int charsExpected) {
  char c;
  char lastChar = '\0';
  int charsReceived = 0;
  bool isLineStart = true;
#ifdef DEBUG
  cout << "charsExpected: " << charsExpected << endl;
#endif
  while (charsReceived < charsExpected) {
    while (read(comfd, &c, 1) < 0);
    if (isLineStart && (c != '>' && c != ' ' && c != '\n' && c != '\r')) {isLineStart = false;}
    if (!isLineStart) {++charsReceived;}
#ifdef DEBUG
    cout << "'" << c << "' " << (int)c << "\t" << charsReceived << " isLineStart: " << isLineStart << endl;
#else
    cout << c << flush;
#endif
    if (!isLineStart && (c == '\r' || c == '\n')) {isLineStart = true;}
    if (isLineStart && lastChar == '>' && c == ' ') {isLineStart = false;}

    lastChar = c;
  }
}

void getAllResponses(int comfd, int linesExpected) {
#ifdef DEBUG
  cout << "linesExpected: " << linesExpected << endl;
#endif
  char c;
  char lastChar = '\0';
  int linesReceived = 0;
  while (linesReceived < linesExpected) {
    while (read(comfd, &c, 1) < 0);
    if ((lastChar == '\n' || lastChar == '\0') && c == '>') {++linesReceived;}
#ifdef DEBUG
    cout << "'" << c << "'" << endl;
#else
    cout << c << flush;
#endif
    lastChar = c;
#ifdef DEBUG
    cout << linesReceived << endl;
#endif
  }
#ifdef DEBUG
  cout << "linesReceived: " << linesReceived << endl;
#endif
}

int main(int argc, char* argv[]) {
  if (argc < 3) {
    cout << "Usage: fileToNxt /dev/[device] (-checkPort | filename) [-quit]" << endl;
    return 1;
  }

  int comfd = openSerial(argv[1]);

  if (!strcmp("-checkPort", argv[2])) {
    close(comfd);
    return 0;
  }

  ifstream inFile;
  inFile.open(argv[2], ios::in);

  int linesSent = 0, charsSent = 0;
  char c, firstChar = '\0';
  while (!inFile.eof()) {
    inFile.get(c);
    if (firstChar == '\0') {firstChar = c;}
    write(comfd, &c, 1);
    ++charsSent;
    if (c == '\n') {++linesSent;}
  }

#ifdef DEBUG
  cout << "linesSent: " << linesSent << endl;
#endif

  if (argc == 4) {
    matchExpectedChars(comfd, charsSent - 1); // Sends a non-echoed double newline at the end
  } else {
    getAllResponses(comfd, linesSent);
  }

  close(comfd);

  return 0;
}
